package chabernac.proxyserver;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

/**
 * Copyright (c) 2010 Axa Holding Belgium, SA. All rights reserved.
 * This software is the confidential and proprietary information of the AXA Group.
 */

public class ProxyServer implements Runnable{
  private static Logger LOGGER = Logger.getLogger( ProxyServer.class );

  private ExecutorService myService = null;
  private ServerSocket myServerSocket = null;
  private SocketFactory myProxySocketFactory = null;
  private iAuthenticationProvider myAuthenticationProvider = null;

  public ProxyServer(int aNrOfThreads, String aDelegateProxy, int aDelegateProxyPort, iAuthenticationProvider anAuthenticationProvider) throws UnknownHostException{
    myService = Executors.newFixedThreadPool( aNrOfThreads + 1 );
    myProxySocketFactory = new SocketFactory(aDelegateProxy, aDelegateProxyPort);
    myAuthenticationProvider = anAuthenticationProvider;
  }

  public void start(){
    myService.execute( this );
  }

  public void run(){
    try{
      myServerSocket = new ServerSocket(9999);
      while(true){
        Socket theClientSocket = myServerSocket.accept();
        myService.execute( new SocketHandler(theClientSocket) );
      }
    }catch(Exception e){
      LOGGER.error( "Could not start proxy server", e );
    }
  }

  public void stop(){
    if(myServerSocket != null){
      try {
        myServerSocket.close();
      } catch ( IOException e ) {
        LOGGER.error( "Could not close server socket", e );
      }
    }
  }

  private class SocketHandler implements Runnable{
    private Socket mySocket = null;
    public SocketHandler(Socket aSocket){
      mySocket = aSocket;
    }

    public void run(){
      Socket theProxySocket  = null;
      try{
        ProxyWorker theWorker = new ProxyWorker(mySocket, myProxySocketFactory, myAuthenticationProvider);
        theWorker.run();
      }catch(Exception e){
        LOGGER.error("An error occured while connecting sockets", e);
      } finally {
        if(theProxySocket != null){
          try {
            theProxySocket.close();
          } catch ( IOException e ) {
          }
        }
        if(mySocket != null){
          try {
            mySocket.close();
          } catch ( IOException e ) {
          }
        }
      }
    }
  }
  
  public static void main(String args[]) throws NumberFormatException, UnknownHostException{
    BasicConfigurator.configure();
    Logger.getRootLogger().setLevel( Level.ERROR );
    ProxyServer theServer  = new ProxyServer(Integer.parseInt( args[0] ), args[1], Integer.parseInt(args[2]), new AuthenticationProviderPopup());
    theServer.start();
  }

}
